package com.sample.springbatch.job.config;

import com.sample.springbatch.job.dao.MyJdbcExecutionContextDao;
import com.sample.springbatch.job.dao.MyJdbcJobExecutionDao;
import com.sample.springbatch.job.dao.MyJdbcJobInstanceDao;
import com.sample.springbatch.job.dao.MyJdbcStepExecutionDao;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.jsr.JsrJobParametersConverter;
import org.springframework.batch.core.jsr.launch.JsrJobOperator;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.ExecutionContextSerializer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.*;
import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;
import org.springframework.batch.support.DatabaseType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.jdbc.support.lob.LobHandler;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.sql.Types;

import static org.springframework.batch.support.DatabaseType.SYBASE;

/**
 * Batch Job 公共的配置
 *
 * Created by zwg on 2017/9/12.
 */
@Configuration
public class CommonConfig {


    @Autowired
    PlatformTransactionManager transactionManager;


    @Autowired
    JobRepository jobRepository;

    //TODO 应该使用配置文件的内容  这里设置默认值
    private String tablePrefix = "BATCH_";
    private int maxVarCharLength = AbstractJdbcBatchMetadataDao.DEFAULT_EXIT_MESSAGE_LENGTH;

    @Autowired
    public DataSource dataSource;



    @Bean
    public SchedulerFactoryBean SchedulerFactoryBean(){
        return new org.springframework.scheduling.quartz.SchedulerFactoryBean();
    }

    /**
     * 提供异步处理的JobLauncher
     * @return
     * @throws Exception
     */
    @Bean
    protected JobLauncher asyncJobLauncher() throws Exception {
        SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
        jobLauncher.setJobRepository(jobRepository);
        //提供异步处理现场
        jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor());
        jobLauncher.afterPropertiesSet();
        return jobLauncher;
    }


    ///////////////////////////////////////////////////////

    @Autowired
    JobExplorer jobExplorer;
    /*@Bean
    public SimpleJobExplorer jobExplorer() throws Exception {
        SimpleJobExplorer  jobExplorer =new SimpleJobExplorer(myJdbcJobInstanceDao(),
                myJdbcJobExecutionDao(),
                myJdbcStepExecutionDao(),
                myJdbcExecutionContextDao());

        return jobExplorer;
    }*/

    @Bean
    public JsrJobOperator jsrJobOperator() throws Exception{
        JsrJobParametersConverter jobParametersConverter = new JsrJobParametersConverter(dataSource);
        jobParametersConverter.afterPropertiesSet();
        JsrJobOperator jsrJobOperator = new JsrJobOperator(jobExplorer, jobRepository, jobParametersConverter, transactionManager);
        jsrJobOperator.afterPropertiesSet();
        return jsrJobOperator;
    }


    ///////////////////////////////////////////////////////




    @Bean
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(this.dataSource);
    }



    @Bean
    public MyJdbcJobInstanceDao myJdbcJobInstanceDao(){
        MyJdbcJobInstanceDao dao = new MyJdbcJobInstanceDao();
        dao.setJdbcTemplate(this.jdbcTemplate());
        dao.setTablePrefix(tablePrefix);

        try {
            String databaseType = DatabaseType.fromMetaData(this.dataSource).name();
            DataFieldMaxValueIncrementerFactory incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(this.dataSource);
            dao.setJobIncrementer(incrementerFactory.getIncrementer(databaseType, tablePrefix + "JOB_SEQ"));
            dao.afterPropertiesSet();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dao;
    }

    private String getDatebaseType() throws MetaDataAccessException {
        return DatabaseType.fromMetaData(this.dataSource).name();
    }

    private DataFieldMaxValueIncrementer getIncrementer(String table) throws MetaDataAccessException {
        DataFieldMaxValueIncrementerFactory incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(this.dataSource);
        return incrementerFactory.getIncrementer(getDatebaseType(),table);
    }



    @Bean
    protected MyJdbcJobExecutionDao myJdbcJobExecutionDao() throws Exception {
        MyJdbcJobExecutionDao dao = new MyJdbcJobExecutionDao();
        dao.setDataSource(dataSource);
        dao.setJobExecutionIncrementer(getIncrementer(tablePrefix + "JOB_EXECUTION_SEQ"));
        dao.setTablePrefix(tablePrefix);
        dao.setClobTypeToUse(determineClobTypeToUse(getDatebaseType()));
        dao.setExitMessageLength(maxVarCharLength);
        dao.afterPropertiesSet();
        return dao;
    }

    @Bean
    protected MyJdbcStepExecutionDao myJdbcStepExecutionDao() throws Exception {
        MyJdbcStepExecutionDao dao = new MyJdbcStepExecutionDao();
        dao.setDataSource(dataSource);
        dao.setStepExecutionIncrementer(getIncrementer(tablePrefix + "STEP_EXECUTION_SEQ"));
        dao.setTablePrefix(tablePrefix);
        dao.setClobTypeToUse(determineClobTypeToUse(getDatebaseType()));
        dao.setExitMessageLength(maxVarCharLength);
        dao.afterPropertiesSet();
        return dao;
    }

    @Bean
    protected MyJdbcExecutionContextDao myJdbcExecutionContextDao() throws Exception {
        MyJdbcExecutionContextDao dao = new MyJdbcExecutionContextDao();
        dao.setJdbcTemplate(this.jdbcTemplate());
        dao.setTablePrefix(tablePrefix);
        dao.setClobTypeToUse(determineClobTypeToUse(getDatebaseType()));
        LobHandler lobHandler = new DefaultLobHandler();
        if (lobHandler != null) {
            dao.setLobHandler(lobHandler);
        }
        dao.setSerializer(getSerializer());
        dao.afterPropertiesSet();
        // Assume the same length.
        dao.setShortContextLength(maxVarCharLength);
        return dao;
    }




    private ExecutionContextSerializer getSerializer() throws Exception {
        XStreamExecutionContextStringSerializer defaultSerializer = new XStreamExecutionContextStringSerializer();
        defaultSerializer.afterPropertiesSet();

        return defaultSerializer;
    }

    private int determineClobTypeToUse(String databaseType) {
        if (SYBASE == DatabaseType.valueOf(databaseType.toUpperCase())) {
            return Types.LONGVARCHAR;
        }
        else {
            return Types.CLOB;
        }
    }
}
